﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    public class GenericConstrain
    {
        public void GenericConstrainTest()
        {
            ClassTtwo<string> c1 = new ClassTtwo<string>();

            ClassTthree<int> c2 = new ClassTthree<int>();
            c2.customeT = 123;
            Console.WriteLine(c2.ToString());
            
            //必须要实现了I1、I2接口的类才能当泛型参数传入ClassTfour
            ClassTfour<ClassToClassTfour> c4 = new ClassTfour<ClassToClassTfour>();
            ClassToClassTfour ctc = new ClassToClassTfour();
            c4.customT = ctc;
            c4.testT();
        }

    }

    //每个泛型参数最多有一个主约束，主约束指定泛型参数必须是或者是继承自某个引用类型。
    //可以有多个次约束，次约束的语法基本相同，但它规定的是某个泛型参数必须实现了所有次约束指定的接口
    class ClassTone<T> where T : Exception
    {
        private T TException;
        public ClassTone(T t)
        {
            TException = t;
        }
        public override string ToString()
        {
            return TException.Source;//主约束保证了TException拥有Source成员
        }

    }

    //主约束限定T是引用类型
    class ClassTtwo<T> where T : class
    {
        private T customT;
        public void Clear()
        {
            customT = null; //引用类型可以设置为null
        }

    }

    //主约束限定T是值类型
    class ClassTthree<T> where T : struct
    {
        public T customeT;
        public override string ToString()
        {
            return customeT.ToString(); //值类型，不会引发NullReferenceException异常
        }
    }

    //次约束就强制要求实现接口
    class ClassTfour<T> where T : I1, I2
    {
        public  T customT;
        public void testT()
        {
            customT.IFunc1();
            customT.IFunc2();
        }
    }

    class ClassToClassTfour : I1, I2
    {
        public void IFunc1()
        {
            Console.WriteLine("实现了I1");
        }

        public void IFunc2()
        {
            Console.WriteLine("实现了I2");
        }
    }

    interface I1
    {
        void IFunc1();
    }

    interface I2
    {
        void IFunc2();
    }
}
